package com.nidu.demo.menu.ability;

import com.alibaba.cola.exception.BizException;
import com.nidu.demo.common.constants.Constants;
import com.nidu.demo.common.enums.MenuTypeEnum;
import com.nidu.demo.common.enums.StatusEnum;
import com.nidu.demo.common.exception.ErrorCodeConstants;
import com.nidu.demo.menu.gateway.MenuGateway;
import com.nidu.demo.menu.model.Menu;
import com.nidu.demo.role.gateway.RoleMenuGateway;
import com.nidu.demo.role.model.RoleMenu;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class MenuDomainService {

    private final MenuGateway gateway;

    private final RoleMenuGateway roleMenuGateway;

    /**
     * 检查名称是否重复
     * @param name
     * @param excludeId
     */
    public void validateDuplicate(String name, Long excludeId) {
        Menu menu = gateway.getByName(name);
        if(menu != null){
            if(excludeId == null){
                throw new BizException(ErrorCodeConstants.MENU_NAME_DUPLICATE.getCode(),
                        ErrorCodeConstants.MENU_NAME_DUPLICATE.getMessage());
            } else if (!excludeId.equals(menu.getId())) {
                throw new BizException(ErrorCodeConstants.MENU_NAME_DUPLICATE.getCode(),
                        ErrorCodeConstants.MENU_NAME_DUPLICATE.getMessage());
            }
        }
    }

    /**
     * 检查父菜单是否启用
     * @param parentId
     */
    public void validateParentId(Long parentId){
        if(parentId != null && !parentId.equals(Constants.ROOT_MENU_ID)){
            Menu parent = gateway.getById(parentId);
            if (parent == null) {
                throw new BizException(ErrorCodeConstants.MENU_PARENT_NOT_FOUND.getCode(),
                        ErrorCodeConstants.MENU_PARENT_NOT_FOUND.getMessage());
            }
            if(StatusEnum.DISABLE.getValue().equals(parent.getStatus())){
                throw new BizException(ErrorCodeConstants.MENU_PARENT_STATUS_DISABLE.getCode(),
                        ErrorCodeConstants.MENU_PARENT_STATUS_DISABLE.getMessage());
            }
        }
    }

    /**
     * 检查子菜单是否启用
     * @param menus
     */
    public void validateChildren(List<Menu> menus){
        // 如果是父菜单，检查所有子菜单状态，按钮状态不需要检查
        if (!menus.isEmpty()) {
            for (Menu child : menus) {
                boolean isNotButton = !MenuTypeEnum.BUTTON.getType().equals(child.getMenuType());
                boolean isEnabled = StatusEnum.ENABLE.getValue().equals(child.getStatus());
                if (isNotButton && isEnabled) {
                    throw new BizException(ErrorCodeConstants.MENU_HAS_CHILD.getCode(),
                            ErrorCodeConstants.MENU_HAS_CHILD.getMessage());
                }
            }

        }
    }

    /**
     * 检查是否被角色引用
     * @param menuIds
     */
    public void validateRoleUse(Set<Long> menuIds){
        Map<Long, List<RoleMenu>> roleMenuMap = roleMenuGateway.getByMenuIds(menuIds);
        if (!roleMenuMap.isEmpty()) {
            throw new BizException(ErrorCodeConstants.MENU_HAS_ROLE.getCode(),
                    ErrorCodeConstants.MENU_HAS_ROLE.getMessage());
        }
    }

    /**
     * 更新状态
     * @param menuId
     * @param status
     */
    public void updateStatus(Long menuId, StatusEnum status) {
        switch (status){
            case ENABLE:
                // 如果是子菜单，检查父菜单状态是否启用
                Menu menu = gateway.getById(menuId);
                validateParentId(menu.getParentId());
                gateway.updateStatus(menuId, StatusEnum.ENABLE.getValue());
                break;
            case DISABLE:
                // 如果是父菜单，检查子菜单状态是否禁用
                List<Menu> children = gateway.getByParentId(menuId);
                validateChildren(children);
                gateway.updateStatus(menuId, StatusEnum.DISABLE.getValue());
                break;
        }
    }

    @Transactional
    public void deleteMenu(Long menuId){

        List<Menu> children = gateway.getByParentId(menuId);

        // 1. 是否存在子菜单或按钮
        validateChildren(children);

        Set<Long> menuIds = new HashSet<>();
        menuIds.add(menuId);
        if (!children.isEmpty()){
            List<Long> childrenIds = children.stream().map(Menu::getId).collect(Collectors.toList());
            menuIds.addAll(childrenIds);
        }

        // 2. 是否被角色绑定
        validateRoleUse(menuIds);

        // 3. 执行逻辑删除
        roleMenuGateway.removeMenusRoles(menuIds);
        gateway.deleteByIds(menuIds);
    }

    @Transactional
    public void deleteMenus(Set<Long> menuIds) {
        // 最终要删除的全部菜单ID（包括按钮）
        Set<Long> allDeleteIds = new HashSet<>();

        for (Long menuId : menuIds) {
            // 1. 子菜单校验
            List<Menu> children = gateway.getByParentId(menuId);
            validateChildren(children); // 有启用子菜单将抛异常

            // 2. 汇总要删除的ID
            allDeleteIds.add(menuId);
            if (!children.isEmpty()) {
                allDeleteIds.addAll(children.stream().map(Menu::getId).collect(Collectors.toList()));
            }
        }

        // 3. 检查角色引用（一次性）
        validateRoleUse(allDeleteIds); // 任意引用都会抛异常

        // 4. 删除角色-菜单关联
        roleMenuGateway.removeMenusRoles(allDeleteIds);

        // 5. 执行逻辑删除
        gateway.deleteByIds(allDeleteIds);
    }
} 